package com.ryl.yomall.list.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ryl.yomall.list.service.ListService;
import com.ryl.yomall.list.dao.GoodsDao;
import com.ryl.yomall.model.list.*;
import com.ryl.yomall.model.product.BaseCategoryView;
import com.ryl.yomall.model.product.BaseTrademark;
import com.ryl.yomall.model.product.SkuAttrValue;
import com.ryl.yomall.model.product.SkuInfo;
import com.ryl.yomall.product.client.ProductFeignClient;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.Nested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Date 8:37
 * @Author ryl
 */
@Service
public class ListServiceImpl implements ListService {
    @Autowired
    private GoodsDao goodsDao;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    /**
     * 商品上架 到ES库
     */
    @Override
    public void onSale(Long skuId) {
        Goods goods=new Goods ();
        //补全数据
        //查询sku_info数据
        SkuInfo skuInfo = productFeignClient.getSkuInfo ( skuId );
        if(skuInfo !=null){
            //ID
            goods.setId(skuInfo.getId());
            //图片
            goods.setDefaultImg(skuInfo.getSkuDefaultImg());
            //标题
            goods.setTitle(skuInfo.getSkuName());
            //价格
            goods.setPrice(skuInfo.getPrice().doubleValue());
            ////////////////////////////////////////////////////
            //时间
            goods.setCreateTime(new Date ());
            ///////////////////////////////////////////////////
            //查询 base_trademark
            BaseTrademark baseTrademark = productFeignClient.getBaseTrademark(skuInfo.getTmId());
            //品牌ID
            goods.setTmId(baseTrademark.getId());
            //品牌名称
            goods.setTmName(baseTrademark.getTmName());
            //品牌的Logo
            goods.setTmLogoUrl(baseTrademark.getLogoUrl());
            ////////////////////////////////////////////////////
            //查询一二三级分类 视图 base_category_view
            BaseCategoryView baseCategoryView = productFeignClient.
                    getBaseCategoryView(skuInfo.getCategory3Id());
            goods.setCategory1Id(baseCategoryView.getCategory1Id());
            goods.setCategory1Name(baseCategoryView.getCategory1Name());
            goods.setCategory2Id(baseCategoryView.getCategory2Id());
            goods.setCategory2Name(baseCategoryView.getCategory2Name());
            goods.setCategory3Id(baseCategoryView.getCategory3Id());
            goods.setCategory3Name(baseCategoryView.getCategory3Name());
            //查询平台属性表  （3张表）
            List<SkuAttrValue> baseAttrInfoAndBaseAttrValue = productFeignClient.
                    getBaseAttrInfoAndBaseAttrValue(skuId);

            List<SearchAttr> attrs = baseAttrInfoAndBaseAttrValue.stream().map((skuAttrValue) -> {
                SearchAttr searchAttr = new SearchAttr();
                //平台属性ID
                searchAttr.setAttrId(skuAttrValue.getBaseAttrInfo().getId());
                //平台属性名称
                searchAttr.setAttrName(skuAttrValue.getBaseAttrInfo().getAttrName());
                //平台属性值名称
                searchAttr.setAttrValue(skuAttrValue.getBaseAttrValue().getValueName());
                return searchAttr;
            }).collect( Collectors.toList());
            goods.setAttrs(attrs);
            //添加 、修改 根据ID 存在了修改  不存在就是添加
            goodsDao.save(goods);
        }

    }
    /**
     * 商品下架 ,从索引库删除
     */
    @Override
    public void cancelSale(Long skuId) {
       goodsDao.deleteById ( skuId );
    }
    /**
     * 更新热度
     */
    @Override
    public void hotScore(Long skuId) {

        //1.更新redis缓存
        String name="hotScore";
        Double score = redisTemplate.opsForZSet ( ).incrementScore ( name ,skuId ,1 );
        //2.达到一定数量添加到索引库
        if(score%10==0){
            Goods goods = goodsDao.findById ( skuId ).get ( );
            if(goods != null){
                goods.setHotScore ( Math.round ( score ) );
                goodsDao.save (  goods);
            }
        }

    }

    /**
     * 返回搜索内容,开始搜索
     * SearchResponseVo 将来要返回值的对象
     */
    @Override
    public SearchResponseVo list(SearchParam searchParam) {
        //构建请求对象
        SearchRequest searchRequest=buildSearchRequest(searchParam);
        SearchResponse searchResponse=null;
        //执行搜索ES
        try {

            searchResponse = restHighLevelClient.search ( searchRequest ,RequestOptions.DEFAULT );
        } catch (IOException e) {
            e.printStackTrace ( );
        }
        //解析结果
        SearchResponseVo vo=parseSearchResponse(searchResponse);
        //当前页
        vo.setPageNo(searchParam.getPageNo());
        //每页数
        vo.setPageSize(searchParam.getPageSize());
        //计算总页数= （总条数 + 每页数 -1）/每页数
        long totalPages = (vo.getTotal() + vo.getPageSize() - 1) / vo.getPageSize();
        vo.setTotalPages(totalPages);
        return vo;

    }

    /**
     * 解析结果
     */
    private SearchResponseVo parseSearchResponse(SearchResponse searchResponse) {
        SearchResponseVo vo = new SearchResponseVo();
        //1:总条数
        SearchHits hits = searchResponse.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println("总条数：" + totalHits);
        vo.setTotal(totalHits);
        //2:商品数据
        SearchHit[] hits1 = hits.getHits();
        List<Goods> goodsList = Arrays.stream(hits1).map((hit) -> {
            String sourceAsString = hit.getSourceAsString();
            Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(null != highlightFields){
                HighlightField title = highlightFields.get("title");
                if(title != null){
                    String string = title.fragments()[0].toString();
                    System.out.println(string);
                    goods.setTitle(string);
                }
            }
            return goods;
        }).collect(Collectors.toList());
        vo.setGoodsList(goodsList);
        //解析品牌集合
        Map<String, Aggregation> stringAggregationMap =
                searchResponse.getAggregations().asMap();
        ParsedLongTerms tmIdAgg = (ParsedLongTerms) stringAggregationMap.get("tmIdAgg");
        //1 2 4
        List<SearchResponseTmVo> tmVoList = tmIdAgg.getBuckets().stream().map( bucket -> {
            SearchResponseTmVo tmVo = new SearchResponseTmVo();
            //品牌ID
            tmVo.setTmId(Long.parseLong(bucket.getKeyAsString()));
            //品牌名称
            ParsedStringTerms tmNameAgg = ((Terms.Bucket) bucket).
                    getAggregations().get("tmNameAgg");
            tmVo.setTmName(tmNameAgg.getBuckets().get(0).getKeyAsString());
            //品牌Logo
            ParsedStringTerms tmLogoUrlAgg = ((Terms.Bucket) bucket).
                    getAggregations().get("tmLogoUrlAgg");
            tmVo.setTmLogoUrl(tmLogoUrlAgg.getBuckets().get(0).getKeyAsString());
            return tmVo;
        }).collect(Collectors.toList());
        vo.setTrademarkList(tmVoList);
        //解析平台属性
        Nested attrsAgg = (Nested) stringAggregationMap.get("attrsAgg");
        Aggregations aggregations = attrsAgg.getAggregations();
        Terms attrIdAgg = aggregations.get("attrIdAgg");
        List<SearchResponseAttrVo> responseAttrVoList = attrIdAgg.getBuckets().stream().map(bucket -> {
            SearchResponseAttrVo attrVo = new SearchResponseAttrVo();
            //一个平台属性Id
            String attrId = ((Terms.Bucket) bucket).getKeyAsString();
            attrVo.setAttrId(Long.parseLong(attrId));
            //一个平台属性名称
            Terms attrNameAgg = ((Terms.Bucket) bucket).getAggregations().get("attrNameAgg");
            attrVo.setAttrName(attrNameAgg.getBuckets().get(0).getKeyAsString());
            //多个平台属性值
            Terms attrValueAgg = ((Terms.Bucket) bucket).getAggregations().get("attrValueAgg");
            attrVo.setAttrValueList(attrValueAgg.getBuckets().stream()
                    .map(Terms.Bucket::getKeyAsString).collect(Collectors.toList()));
            return attrVo;
        }).collect(Collectors.toList());
        vo.setAttrsList(responseAttrVoList);
        return vo;
    }


    /**
     * 构建搜索请求对象
     */
    private SearchRequest buildSearchRequest(SearchParam searchParam) {
        //请求对象
        SearchRequest searchRequest = new SearchRequest (  );
        //构建搜索条件对象
        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder (  );
        //开始向条件对象设置条件
        //创建一个组合对象
        BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery ();
        //1.关键词
        String keyword = searchParam.getKeyword ( );
        if(!StringUtils.isEmpty ( keyword )){

            boolQueryBuilder.must ( QueryBuilders.matchQuery ( "title",keyword ).operator ( Operator.AND) );
        }else{
            boolQueryBuilder.must  ( QueryBuilders.matchAllQuery () );
        }
        // 2.过滤条件
        // 品牌  品牌Id:品牌名称
        String trademark = searchParam.getTrademark ( );
        if(! StringUtils.isEmpty ( trademark )){
            String[] split = StringUtils.split ( trademark ,":" );
            if(split != null && split.length>0){
            boolQueryBuilder.filter ( QueryBuilders.termQuery ( "tmId",split[0] ) );
            }
        }
        // 3.一二三级分类
        Long category1Id = searchParam.getCategory1Id ( );
        if( null != category1Id){
            boolQueryBuilder.filter ( QueryBuilders.termQuery ( "category1Id",category1Id ) );
        }
        Long category2Id = searchParam.getCategory2Id ( );
        if( null != category2Id){
            boolQueryBuilder.filter ( QueryBuilders.termQuery ( "category2Id",category2Id ) );
        }
        Long category3Id = searchParam.getCategory3Id ( );
        if( null != category3Id){
            boolQueryBuilder.filter ( QueryBuilders.termQuery ( "category3Id",category3Id ) );
        }
        //      平台属性
        String[] props = searchParam.getProps();
        if(null != props && props.length > 0){
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();//[  ]
            for (String prop : props) {
                //子组合对象
                BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery();//{}
                //prop : 平台属性ID:平台属性值名称:平台属性名称
                String[] p = prop.split(":");
                subBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",p[0]));
                subBoolQuery.must(QueryBuilders.termQuery("attrs.attrValue",p[1]));
                //嵌套关系
                boolQuery.must(QueryBuilders.nestedQuery("attrs",subBoolQuery,
                        ScoreMode.None));
            }
            //平台属性
            boolQueryBuilder.filter(boolQuery);
        }
        //开始向条件对象设置组合对象
        searchSourceBuilder.query(boolQueryBuilder);

        // 4、排序 order   1:asc ..
        String order = searchParam.getOrder();
        if(!StringUtils.isEmpty(order)){
            String[] o = order.split(":");
            if(null != o && o.length == 2){
                String s = "";
                switch (o[0]){//很多
                    case "1": s = "hotScore" ; break;
                    case "2": s = "price" ; break;
                }
                searchSourceBuilder.sort(s,
                        o[1].equalsIgnoreCase("asc")? SortOrder.ASC :SortOrder.DESC);
            }
        }else{
            //排序  默认综合排序  按照热度排序 （公平）
            searchSourceBuilder.sort("hotScore",SortOrder.DESC);
        }
        //5、分页   limit 开始行,每页数
        Integer pageNo = searchParam.getPageNo();
        Integer pageSize = searchParam.getPageSize();
        searchSourceBuilder.from((pageNo -1)*pageSize);
        searchSourceBuilder.size(pageSize);
        //6:高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title")
                .preTags("<font color='red'>")
                .postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);
        //7：根据关键词 查询 品牌集合  8个数据  ： 华为2  小米1  苹果5
        // 华为 小米  苹果    group by  ==  ES 索引库 聚合 select max(id) as idddd from
        // 品牌ID 品牌名称 品牌Logo
        searchSourceBuilder.aggregation(
                AggregationBuilders.terms("tmIdAgg").field("tmId")
                        .subAggregation(AggregationBuilders.terms("tmNameAgg").field("tmName"))
                        .subAggregation(AggregationBuilders.terms("tmLogoUrlAgg").field("tmLogoUrl")));
        //8:平台属性聚合
        searchSourceBuilder.aggregation(
                AggregationBuilders.nested("attrsAgg","attrs")
                        .subAggregation(AggregationBuilders.terms("attrIdAgg").field("attrs.attrId")
                                .subAggregation(AggregationBuilders.terms("attrNameAgg").field("attrs.attrName"))
                                .subAggregation(AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue")))
        );
        // 将构建搜索条件对象设置给请求对象
        searchRequest.source ( searchSourceBuilder );
        //设置索引库
        searchRequest.indices ( "goods" );

        return searchRequest;

    }


}
